﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Windows.Media.Imaging;
// MakePanoForGoogle, Copyright Mirosław M. Mączka.  All Rights Reserved. This code released under the terms of the Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.)

namespace MakePanoForGoogle
{
    class ImageManipulations
    {
        public static void ResetInfo()
        {
            IsResized = false;
            ImageQuality = 100;
        }
        //##################################################################################################################################
        public static bool IsResized { get; set; }

        public static async Task<System.Drawing.Image> ResizeIfNeeded(System.Drawing.Image img, double maxMegaPixels)
        {
            IsResized = false;
            //System.Drawing.Image img = img0.Clone() as System.Drawing.Image;
            GC.Collect();
            double newAverageDimension = Math.Sqrt(MainWindow.megaOfPixels * maxMegaPixels);
            int currentWidth = img.Width;
            int currentHeight = img.Height;
            double currentArea = currentWidth * currentHeight;
            double currentAverageDimension = Math.Sqrt(currentArea);
            if ((currentArea / MainWindow.megaOfPixels) > maxMegaPixels)
            {
                IsResized = true;
                double multiplicator = newAverageDimension / currentAverageDimension;
                int newHeight = (int)(currentHeight * multiplicator);
                int newWidth = (int)(currentWidth * multiplicator);
                //
                System.Drawing.Image imgOut = await ResizeBmplcl(img, newWidth, newHeight);
                GC.Collect();
                return imgOut;
                //
            }
            //
            return img;
        }

        //http://forums.codeguru.com/showthread.php?463819-RESOLVED-g-DrawImage-Out-of-memory
        internal static async Task<System.Drawing.Image> ResizeBmplcl(System.Drawing.Image imgIn, int newWidth, int newHeight)
        {
            System.Drawing.Bitmap resizedBitmap = new System.Drawing.Bitmap(newWidth, newHeight);
            resizedBitmap.SetResolution(MainWindow.DPI, MainWindow.DPI);

            try
            {
                using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage((System.Drawing.Image)resizedBitmap))
                {
                    if (true)
                    {
                        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                        g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                        g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                    }
                    try
                    {
                        g.DrawImage(imgIn, new System.Drawing.Rectangle(0, 0, newWidth, newHeight), 0, 0, imgIn.Width, imgIn.Height, System.Drawing.GraphicsUnit.Pixel);
                    }
                    catch (Exception ex)
                    {
                        System.Windows.MessageBox.Show(ex.Message, "ResizeBmplcl 1");
                    }
                }
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show(ex.Message, "ResizeBmplcl 2");
            }
            //
            GC.Collect();
            return (System.Drawing.Image)resizedBitmap;
        }
        //##################################################################################################################################
        public static int ImageQuality { get; set; }

        public static async Task<int> SaveBitmapWithSize(System.Drawing.Image img, string outputFileName, int maxMegaBytes)
        {
            long jpgQuality = 100L; ImageQuality = (int)jpgQuality;
            MemoryStream ms = new MemoryStream();
            System.Drawing.Imaging.EncoderParameters encoderParameters = new System.Drawing.Imaging.EncoderParameters(1);
            //
            GC.Collect();
            for (int i = 0; i < 30; i++)
            {
                encoderParameters.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, jpgQuality);
                ms.Position = 0;
                img.Save(ms, GetEncoder(System.Drawing.Imaging.ImageFormat.Jpeg), encoderParameters);
                if ((ms.Position / MainWindow.megaOfBytes) < maxMegaBytes)
                {
                    if (File.Exists(outputFileName)) File.Delete(outputFileName);
                    using (FileStream fs = File.Open(outputFileName, FileMode.CreateNew))
                    {
                        //fs.Write(ms.ToArray(), 0, (int)ms.Position);
                        await fs.WriteAsync(ms.ToArray(), 0, (int)ms.Position);
                    }
                    GC.Collect();
                    ImageQuality = (int)jpgQuality;
                    return (int)jpgQuality;
                }
                jpgQuality -= 1;
            }
            System.Windows.MessageBox.Show("Image length too big!","Save as Jpg");
            return (int)jpgQuality;
        }


        public static async Task<int> SaveBitmapAsIs(System.Drawing.Image img, string outputFileName)
        {
            long jpgQuality = 95L; ImageQuality = (int)jpgQuality;
            MemoryStream ms = new MemoryStream();
            System.Drawing.Imaging.EncoderParameters encoderParameters = new System.Drawing.Imaging.EncoderParameters(1);
            //
            GC.Collect();
            encoderParameters.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, jpgQuality);
            ms.Position = 0;
            img.Save(ms, GetEncoder(System.Drawing.Imaging.ImageFormat.Jpeg), encoderParameters);
            if (File.Exists(outputFileName)) File.Delete(outputFileName);
            using (FileStream fs = File.Open(outputFileName, FileMode.CreateNew))
            {
                //fs.Write(ms.ToArray(), 0, (int)ms.Position);
                await fs.WriteAsync(ms.ToArray(), 0, (int)ms.Position);
            }
            GC.Collect();
            return (int)jpgQuality;
        }
        //##################################################################################################################################
        static System.Drawing.Imaging.ImageCodecInfo GetEncoder(System.Drawing.Imaging.ImageFormat format)
        {
            System.Drawing.Imaging.ImageCodecInfo[] codecs = System.Drawing.Imaging.ImageCodecInfo.GetImageDecoders();
            return codecs.Single(codec => codec.FormatID == format.Guid);
        }
        //##################################################################################################################################
    }//class
}//namespace
